#include<stdio.h>
#include<list>
#include<map>
#include<stack>
#include<malloc.h>
#ifndef SECDVM
#define SECDVM


//#include"gc.h"
enum Instruction{
    I_NIL=1,
    I_ADD,
    I_SUB,
    I_DIV,
    I_MUL,
    I_MOD,
    I_LD,
    I_LDI,//integer
    I_LDS,//string
    I_LDD,//double
    I_LDSY,//symbol
    I_LDC,//char
    I_LDF,//func
    I_LDB,//bool
    I_LDN,//name
    I_AP,
    I_DUM,
    I_RAP,
    I_TAP,//tail call
    I_DAP,//tail recur call
    I_RTN,
    I_CONS,
    I_SEL,
    I_JOIN,
    I_EQ,
    I_GT,
    I_LT,
    I_GE,
    I_LE,
    I_STOP
};

enum ValueType {
    T_Nil,
    T_String,
    T_Integer,
    T_Env,
    T_Float,
    T_Quote,
    T_Pair,
    T_List,
    T_Char,
    T_Symbol,
    T_Lambda,
    T_Cfunc,
    T_Continuation,
};


typedef struct ValueStruct{
    union {
        int ival;
        float fval;
        char cval;
        char *sval;
        void *cfuncval;
        void *closureval;
        char *symbolval;
        std::list<struct ValueStruct *> *listval;
        std::list<struct ValueStruct *> *pairval;
    } val;
    std::list<struct ValueStruct *> *env;
    ValueType t;
    char mark ;
    int length;
} Value;


typedef struct Opcodes{
    Instruction inst;
    union {
        int ival;
        float fval;
        char cval;
        char *sval;
        void *cfuncval;
        void *closureval;
        char *symbolval;
    } constant;
    int level;
    int position;
    struct Opcodes *arg1;
    struct Opcodes *arg2;
    struct Opcodes *next;
}Codes;

typedef struct DumpItem{
    Codes *code;
    std::list<Value *> *env;
    std::stack<Value *> *stack;
}DumpItem;

typedef void (*instruct_func)(void *);
typedef void (*c_func)(void *,Value*);

class SecdVM{
    public :
        std::stack<Value *> *Stack;
        std::list<Value *> *Env;
        Codes *Code;
        instruct_func instructions[512];
        std::list<DumpItem *> *Dump;
        std::map<char*,Value*> *Globals;
        Value *NIL;
        void *gc;
        Value *makeSymbol(char *,int);
        Value *makeString(char *,int);
        Value *makeChar(char);
        Value *makeInteger(int);
        Value *makeFloat(float);
        Value *makeList(Value *,Value *);
        Value *cons(Value *a,Value *b);
        void registCFunc(char *,c_func);
        void registInstruction(Instruction,instruct_func);
        void run(Codes *);
        void reset();
        SecdVM();
        ~SecdVM();

};

void displayValue(Value *val);

Codes *makeLdi(int n);
Codes *makeNil();
Codes *makeAdd();
Codes *makeCons();
Codes *makeStop();
Codes *makeSel(Codes *left,Codes *right);
Codes *makeJoin();
Codes *makeSub();
Codes *makeDiv();
Codes *makeMul();
Codes *makeMod();
Codes *makeLd(int,int);
Codes *makeLds(char *);
Codes *makeLdc(char);
Codes *makeLdf(Codes *);
Codes *makeLdsy(char *);
Codes *makeLdb(int);
Codes *makeLdd(float);
Codes *makeLdN(char *);
Codes *makeAp();
Codes *makeDum();
Codes *makeRap();
Codes *makeTap();
Codes *makeDap();
Codes *makeEq();
Codes *makeGt();
Codes *makeLt();
Codes *makeGe();
Codes *makeLe();



#endif // SECDVM
